package com.mpp.admin.config;

import com.mpp.admin.shiro.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author mapp
 * @des shiro配置
 * @date 2019/2/13
 */
@Configuration
@Import(ResidConfigration.class)
public class ShiroConfiguration {

    // 安全管理器
    @Bean
    public DefaultWebSecurityManager securityManager(RedisTemplate redisTemplate) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        securityManager.setCacheManager(cacheManager(redisTemplate));
        securityManager.setSessionManager(sessionManager(redisTemplate));
        return securityManager;
    }

    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm realm = new MyShiroRealm();
        // 告诉shiro我们使用的加密算法。在验证密码时使用 同样注册时 要采用同样的加密方式
        realm.setCredentialsMatcher(credentialsMatcher());
        realm.setAuthenticationCachingEnabled(false);
        realm.setCachingEnabled(false);
        return realm;
    }

    // 加密算法
    @Bean
    public HashedCredentialsMatcher credentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        // 加密算法的名称
        matcher.setHashAlgorithmName("MD5");
        // 加密的次数
        matcher.setHashIterations(1024);
        return matcher;
    }

    // 会话管理器 此处我进行了自定义回话，用redis存储了用户session。
    @Bean
    public DefaultWebSessionManager sessionManager(RedisTemplate redisTemplate) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(sessionDAO(redisTemplate));
        sessionManager.setSessionIdCookie(cookie());
        return sessionManager;
    }

    // 缓存管理器 RedisCacheManager
    @Bean
    public RedisCacheManager cacheManager(RedisTemplate redisTemplate) {
        return new RedisCacheManager(redisTemplate);
    }

    @Bean
    public RedisCache redisCache(RedisTemplate redisTemplate) {
        return new RedisCache(redisTemplate);
    }

    // 自定义sessionDao
    @Bean
    public RedisSessionDao sessionDAO(RedisTemplate redisTemplate) {
        return new RedisSessionDao(redisCache(redisTemplate));
    }

    @Bean
    public SimpleCookie cookie() {
        SimpleCookie cookie = new SimpleCookie("SHAREJSESSIONID"); //  cookie的name,对应的默认是 JSESSIONID
        return cookie;
    }


//    @Bean
//    public MyFormAuthenticationFilter myFormAuthenticationFilter() {
//        MyFormAuthenticationFilter formAuthenticationFilter = new MyFormAuthenticationFilter();
//        formAuthenticationFilter.setSuccessUrl("/index");
//        return formAuthenticationFilter;
//    }

    // shiro拦截器
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 过滤器
        Map<String, String> filters = new HashMap<>();
        Map<String, Filter> filterHashMap = new HashMap<>();
        filterHashMap.put("myauth", new MyFormAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filterHashMap);
        // 静态资源部拦截
        filters.put("/static/**", "anon");
        // 使用shiro提供的authc 表单过滤器 会拦截所有的请求（/favicon.ico同样会拦截。算是个小坑）
        filters.put("/favicon.ico", "anon");
        filters.put("/layout", "logout");
        // 其他资源需要认证后才能访问 这里我继承了FormAuthenticationFilter 表单认证
        // 因为其已经实现了大部分登录逻辑；我们只需要指定：登录地址/登录失败后错误信息存哪/成功的地址即可。
        filters.put("/**", "myauth");
        // 默认登录页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功页面
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 未授权页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filters);
        return shiroFilterFactoryBean;
    }
}
